Skip to content

PKCS#7 improvements#10760

Open
Frauschi wants to merge 1 commit into
wolfSSL:masterfrom
Frauschi:pkcs7-server-encode
Open

PKCS#7 improvements#10760
Frauschi wants to merge 1 commit into
wolfSSL:masterfrom
Frauschi:pkcs7-server-encode

Conversation

@Frauschi

Copy link
Copy Markdown
Contributor

Summary

Server-side PKCS#7/CMS encode improvements so downstream EST/SCEP enrollment code can drive the existing encoder through the public API instead of hand-rolling DER, plus a related multi-certificate decode bug fix found along the way. All changes are gated under the existing HAVE_PKCS7 - no new build options and no new public functions.

Changes

  1. Allow degenerate (certs-only) SignedData encode

Relaxes the hashOID != 0 requirement in PKCS7_EncodeSigned() when sidType == DEGENERATE_SID. A caller can now produce a degenerate, certs-only SignedData (no signer, no signed attributes, no eContent - the form used by EST /cacerts and SCEP GetCACert responses) entirely through the existing public API:

wc_PKCS7_InitWithCert(pkcs7, cert, certSz);          
/* wc_PKCS7_AddCertificate() */
wc_PKCS7_SetSignerIdentifierType(pkcs7, DEGENERATE_SID);
pkcs7->detached   = 1;
pkcs7->contentOID = DATA;
wc_PKCS7_EncodeSignedData(pkcs7, out, outSz);

The output round-trips through wc_PKCS7_VerifySignedData() (which repopulates pkcs7->cert[]).

  1. Size the signed-attribute array to the actual count

The SignerInfo attribute working array is now sized to the real attribute count instead of a fixed [7] array. An inline buffer (sized MAX_SIGNED_ATTRIBS_SZ, the historical footprint) covers the common case with no heap allocation - important for no-malloc/static-memory builds - and a heap buffer is used only when the count exceeds it. The default-attribute count comes from a single helper (wc_PKCS7_GetDefaultSignedAttribCount()) so the sizing matches the emission logic exactly, and the canned-attribute write is bound-checked against the array capacity so any future drift fails with BUFFER_E rather than overflowing.

This also fixes a latent overflow where the backing array was hardcoded [7] while the bound check used MAX_SIGNED_ATTRIBS_SZ. Profiles such as SCEP CertRep (RFC 8894), which carry several user attributes alongside the CMS auto-defaults, now encode without spurious BUFFER_E. MAX_SIGNED_ATTRIBS_SZ is retained for source compatibility but no longer caps the count (it only sizes the embedded inline buffer).

  1. Document the decoded-attribute value shape

Documents the stable, guaranteed shape of PKCS7DecodedAttrib.value (the contents of the SET OF AttributeValue, with the outer SET tag stripped) so callers can rely on it. Documentation only - no behavior change.

  1. Multi-certificate decode fix (non-streaming)

Bounds the additional-certificate loop in wc_PKCS7_VerifySignedData() against the absolute end of the certificate set (idx + length) rather than the relative length. In NO_PKCS7_STREAM builds the previous bound stopped short and dropped trailing certificates - and, with a large eContent preceding the set, could drop all but the first certificate, causing verification to fail when the signer cert was among those dropped. Streaming builds were unaffected.

Public API

No additions or changes. MAX_SIGNED_ATTRIBS_SZ is retained for source compatibility but no longer caps the attribute count (it now sizes the inline encode-time working buffer).

Tests

Added coverage in pkcs7signed_test:

  • Degenerate (certs-only) encode via the public API, round-tripped through verify.
  • Nine signed attributes (six user + three auto-defaults), exceeding the inline capacity to exercise the heap-fallback path.
  • Decoded-attribute value shape for PrintableString and OCTET STRING.
  • A multi-certificate decode regression with large content that triggers the bound bug under NO_PKCS7_STREAM.

Config-sensitive cases are guarded (MAX_PKCS7_CERTS >= 3; the nine-attribute case requires heap or an enlarged inline array). The multi-cert test only validates the bound fix under NO_PKCS7_STREAM (documented in the test); in streaming builds it is a general multi-cert round-trip check.

Verification

  • Builds clean (-Werror) on the default/streaming configuration.
  • wolfcrypt/test/testwolfcrypt passes (PKCS7signed test passed!).

@Frauschi Frauschi self-assigned this Jun 23, 2026
@Frauschi Frauschi marked this pull request as ready for review June 23, 2026 12:05
@github-actions

Copy link
Copy Markdown

retest this please

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown

@Frauschi Frauschi assigned wolfSSL-Bot and unassigned Frauschi Jun 23, 2026
…ute handling

Server-side PKCS#7 encode improvements that let downstream EST/SCEP enrollment
code (wolfCert) drive the existing encoder through the public API rather than
hand-rolling DER. Everything is gated under the existing HAVE_PKCS7 — no new
build options and no new public functions; the convenience wrappers live
caller-side.

Allow degenerate (certs-only) SignedData encode
  Relax the hashOID != 0 requirement in PKCS7_EncodeSigned() when
  sidType == DEGENERATE_SID, so a caller can produce a certs-only bundle (no
  signer, attributes, or eContent — the form used by EST /cacerts and SCEP
  GetCACert) by selecting DEGENERATE_SID via wc_PKCS7_SetSignerIdentifierType()
  and calling wc_PKCS7_EncodeSignedData(). The output round-trips through
  wc_PKCS7_VerifySignedData().

Size the signed-attribute array to the actual count
  The SignerInfo attribute working array is now sized to the real attribute
  count instead of a fixed [7] array. An inline buffer (sized
  MAX_SIGNED_ATTRIBS_SZ, the historical footprint) covers the common
  allocation-free case; a heap buffer is used only when the count exceeds it.
  The default-attribute count comes from a single helper
  (wc_PKCS7_GetDefaultSignedAttribCount) so the sizing matches the emission
  logic exactly, and the canned-attribute write is bound-checked against the
  array capacity. This also fixes a latent overflow where the backing array was
  hardcoded [7] while the bound check used MAX_SIGNED_ATTRIBS_SZ. The macro is
  retained for source compatibility but no longer caps the count.

Document the decoded-attribute value shape
  Documented the stable shape of PKCS7DecodedAttrib.value (the contents of the
  SET OF AttributeValue, outer SET tag stripped) so callers can rely on it. No
  behavior change.

Fix multi-certificate decode in non-streaming builds
  Bound the additional-certificate loop in wc_PKCS7_VerifySignedData against the
  absolute end of the certificate set (idx + length) rather than the relative
  length. In NO_PKCS7_STREAM builds the old bound dropped trailing certificates
  (all but the first when a large eContent preceded the set), failing
  verification when the signer cert was among those dropped. Streaming builds
  were unaffected.

Tests
  Added coverage in pkcs7signed_test: degenerate certs-only encode via the
  public API, nine-attribute encode (beyond the inline capacity), decoded
  attribute value shape for PrintableString and OCTET STRING, and a
  multi-certificate decode regression with large content that triggers the
  bound bug under NO_PKCS7_STREAM. Config-sensitive cases are guarded.
@Frauschi Frauschi force-pushed the pkcs7-server-encode branch from 59bc162 to 6449ca0 Compare June 23, 2026 17:05
@Frauschi

Copy link
Copy Markdown
Contributor Author

Jenkins retest this please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants